//============================================================================
/// \file   ResizeHandle.cpp
/// \author Uwe Kindler
/// \date   24.10.2022
/// \brief  Implementation of CResizeHandle class
//============================================================================

//============================================================================
//                                   INCLUDES
//============================================================================
#include "ResizeHandle.h"

#include <QDebug>
#include <QStyle>
#include <QStyleOption>
#include <QMouseEvent>
#include <QRubberBand>
#include <QPointer>

#include "ads_globals.h"

namespace ads
{
/**
 * CResizeHandle类的私有数据类（pimpl）
 */
struct ResizeHandlePrivate
{
    CResizeHandle* _this;
    Qt::Edge HandlePosition = Qt::LeftEdge;
    QWidget* Target = nullptr;
    int MouseOffset = 0;
    bool Pressed = false;
    int MinSize = 0;
    int MaxSize = 1;
    QPointer<QRubberBand> RubberBand;
    bool OpaqueResize = false;
    int HandleWidth = 4;

    /**
     * 私有数据构造函数
     */
    ResizeHandlePrivate(CResizeHandle* _public);

    /**
     * 根据方向从位置中提取相应的坐标分量
     */
    int pick(const QPoint& pos) const
    {
        return _this->orientation() == Qt::Horizontal ? pos.x() : pos.y();
    }

    /**
     * 判断方向是否为水平方向
     */
    bool isHorizontal() const
    {
        return _this->orientation() == Qt::Horizontal;
    }

    /**
     * 设置橡皮筋的位置
     */
    void setRubberBand(int Pos);

    /**
     * 计算调整大小的位置和几何形状
     */
    void doResizing(QMouseEvent* e, bool ForceResize = false);
};

// struct ResizeHandlePrivate

// ResizeHandlePrivate构造函数
ResizeHandlePrivate::ResizeHandlePrivate(CResizeHandle *_public) :
    _this(_public)
{
}

// 设置橡皮筋
void ResizeHandlePrivate::setRubberBand(int Pos)
{
    // 如果橡皮筋不存在，创建一个QRubberBand对象
    if (!RubberBand)
    {
        RubberBand = new QRubberBand(QRubberBand::Line, Target->parentWidget());
    }

    // 获取ResizeHandle的边界矩形和左上角坐标
    auto Geometry = _this->geometry();
    auto TopLeft = Target->mapTo(Target->parentWidget(), Geometry.topLeft());

    // 根据ResizeHandle的方向，更新TopLeft坐标
    switch (HandlePosition)
    {
    case Qt::LeftEdge:
    case Qt::RightEdge: TopLeft.rx() += Pos; break;
    case Qt::TopEdge:
    case Qt::BottomEdge: TopLeft.ry() += Pos; break;
    }

    // 更新边界矩形并显示橡皮筋
    Geometry.moveTopLeft(TopLeft);
    RubberBand->setGeometry(Geometry);
    RubberBand->show();
}

// 执行调整大小操作
void ResizeHandlePrivate::doResizing(QMouseEvent* e, bool ForceResize)
{
    // 获取鼠标移动的距离
    int pos = pick(e->pos()) - MouseOffset;

    // 获取目标控件的原始边界矩形和新的边界矩形
    auto OldGeometry = Target->geometry();
    auto NewGeometry = OldGeometry;

    // 根据ResizeHandle的方向，更新NewGeometry
    switch (HandlePosition)
    {
    case Qt::LeftEdge:
        {
            NewGeometry.adjust(pos, 0, 0, 0);
            int Size = qBound(MinSize, NewGeometry.width(), MaxSize);
            pos += (NewGeometry.width() - Size);
            NewGeometry.setWidth(Size);
            NewGeometry.moveTopRight(OldGeometry.topRight());
        }
        break;
    case Qt::RightEdge:
        {
            NewGeometry.adjust(0, 0, pos, 0);
            int Size = qBound(MinSize, NewGeometry.width(), MaxSize);
            pos -= (NewGeometry.width() - Size);
            NewGeometry.setWidth(Size);
        }
        break;
    case Qt::TopEdge:
        {
            NewGeometry.adjust(0, pos, 0, 0);
            int Size = qBound(MinSize, NewGeometry.height(), MaxSize);
            pos += (NewGeometry.height() - Size);
            NewGeometry.setHeight(Size);
            NewGeometry.moveBottomLeft(OldGeometry.bottomLeft());
        }
        break;
    case Qt::BottomEdge:
        {
            NewGeometry.adjust(0, 0, 0, pos);
            int Size = qBound(MinSize, NewGeometry.height(), MaxSize);
            pos -= (NewGeometry.height() - Size);
            NewGeometry.setHeight(Size);
        }
        break;
    }

    // 根据opaqueResize和ForceResize的值，更新目标控件的边界矩形或显示橡皮筋
    if (_this->opaqueResize() || ForceResize)
    {
        Target->setGeometry(NewGeometry);
    }
    else
    {
        setRubberBand(pos);
    }
}

// CResizeHandle构造函数
CResizeHandle::CResizeHandle(Qt::Edge HandlePosition, QWidget* parent) :
    Super(parent),
    d(new ResizeHandlePrivate(this))
{
    d->Target = parent;
    setMinResizeSize(48);
    setHandlePosition(HandlePosition);
}

// CResizeHandle析构函数
CResizeHandle::~CResizeHandle()
{
    delete d;
}


//============================================================================
void CResizeHandle::mouseMoveEvent(QMouseEvent* e)
{
    // 如果鼠标左键没有按下，则返回
    if (!(e->buttons() & Qt::LeftButton))
    {
        return;
    }
    // 执行调整大小操作
    d->doResizing(e);
}
//============================================================================
void CResizeHandle::mousePressEvent(QMouseEvent* e)
{
    // 如果鼠标左键按下
    if (e->button() == Qt::LeftButton)
    {
        // 获取鼠标点击位置的偏移量
        d->MouseOffset = d->pick(e->pos());
        // 设置Pressed为true
        d->Pressed = true;
        // 更新界面
        update();
    }
}
//============================================================================
void CResizeHandle::mouseReleaseEvent(QMouseEvent* e)
{
    // 如果不是透明调整大小，并且鼠标左键释放
    if (!opaqueResize() && e->button() == Qt::LeftButton)
    {
        // 如果存在RubberBand，删除之
        if (d->RubberBand)
        {
            d->RubberBand->deleteLater();
        }
        // 执行调整大小操作
        d->doResizing(e, true);
    }
    // 如果鼠标左键释放
    if (e->button() == Qt::LeftButton)
    {
        // 设置Pressed为false
        d->Pressed = false;
        // 更新界面
        update();
    }
}
//============================================================================
void CResizeHandle::setHandlePosition(Qt::Edge HandlePosition)
{
    // 设置HandlePosition
    d->HandlePosition = HandlePosition;
    switch (d->HandlePosition)
    {
    case Qt::LeftEdge: // 继续执行
    case Qt::RightEdge: 
        // 设置鼠标光标为水平调整大小光标
        setCursor(Qt::SizeHorCursor); 
        break;
    case Qt::TopEdge: // 继续执行
    case Qt::BottomEdge: 
        // 设置鼠标光标为垂直调整大小光标
        setCursor(Qt::SizeVerCursor); 
        break;
    }
    // 设置最大调整大小尺寸
    setMaxResizeSize(d->isHorizontal() ? parentWidget()->height() : parentWidget()->width());
    if (!d->isHorizontal())
    {
        // 设置水平调整大小的SizePolicy
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    }
    else
    {
        // 设置垂直调整大小的SizePolicy
        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
    }
}
//============================================================================
Qt::Edge CResizeHandle::handlePostion() const
{
    // 返回HandlePosition
    return d->HandlePosition;
}
//============================================================================
Qt::Orientation CResizeHandle::orientation() const
{
    switch (d->HandlePosition)
    {
    case Qt::LeftEdge: // 继续执行
    case Qt::RightEdge: 
        // 返回水平方向
        return Qt::Horizontal;
    case Qt::TopEdge: // 继续执行
    case Qt::BottomEdge: 
        // 返回垂直方向
        return Qt::Vertical;
    }
    return Qt::Horizontal;
}
//============================================================================
QSize CResizeHandle::sizeHint() const
{
    QSize Result;
    switch (d->HandlePosition)
    {
    case Qt::LeftEdge: // 继续执行
    case Qt::RightEdge: 
        // 设置Result为Handle的宽度和Target的高度
        Result = QSize(d->HandleWidth, d->Target->height()); 
        break;
    case Qt::TopEdge: // 继续执行
    case Qt::BottomEdge: 
        // 设置Result为Target的宽度和Handle的高度
        Result = QSize(d->Target->width(), d->HandleWidth); 
        break;
    }
    return Result;
}
//============================================================================
bool CResizeHandle::isResizing() const
{
    // 返回Pressed
    return d->Pressed;
}
//============================================================================
void CResizeHandle::setMinResizeSize(int MinSize)
{
    // 设置MinSize
    d->MinSize = MinSize;
}
//============================================================================
void CResizeHandle::setMaxResizeSize(int MaxSize)
{
    // 设置MaxSize
    d->MaxSize = MaxSize;
}
//============================================================================
void CResizeHandle::setOpaqueResize(bool opaque)
{
    // 设置OpaqueResize
    d->OpaqueResize = opaque;
}
//============================================================================
bool CResizeHandle::opaqueResize() const
{
    // 返回OpaqueResize
    return d->OpaqueResize;
}
} // namespace ads

//---------------------------------------------------------------------------
// EOF ResizeHandle.cpp
